﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using Accessibility;
using HalconDotNet;
using Microsoft.Win32;
using QRCode_MS.Models;

namespace QRCode_MS.ViewModels
{
    public class MainWindowViewModel : BaseModel
    {
        /// <summary>
        /// 鼠标按下的坐标
        /// </summary>
        private Point _startPoint;
        /// <summary>
        /// 鼠标松开坐标
        /// </summary>
        private Point _endPoint;
        private Canvas _myCanvas;
        private HWindow _hv_Hanlde;
        private HSmartWindowControlWPF _controlWPF;
        private ShapeType _shapeType = ShapeType.None;


        /// <summary>
        /// 定义加载图像的属性
        /// </summary>
        private HObject _dispImage;
        private HObject _dispROI;
        private HObject _dispXld;
        private string _codeData;
        private double _k;
        private double _tx;
        private double _ty;
        private double _row;
        private double _column;
        private double _row1;
        private double _column1;
        private NewDrawingObject _roi;

        public RectangleModel RectModel { get; set; } = new RectangleModel();

        public SimpleCommand LoadImageCommand { get; private set; }

        public SimpleCommand MouseDownCommand { get; private set; }
        public SimpleCommand MouseMoveCommand { get; private set; }
        public SimpleCommand MouseUpCommand { get; private set; }
        public SimpleCommand DrawRectComand { get; private set; }
        public SimpleCommand DiscernComand { get; private set; }

        public MainWindowViewModel()
        {
            // 初始化命令对象
            LoadImageCommand = new SimpleCommand
            {
                DoExecute = new Action<object>(LoadImage)
            };

            MouseDownCommand = new SimpleCommand { DoExecute = new Action<object>(MouseDown) };
            MouseMoveCommand = new SimpleCommand { DoExecute = new Action<object>(MouseMove) };
            MouseUpCommand = new SimpleCommand { DoExecute = new Action<object>(MouseUp) };
            DrawRectComand = new SimpleCommand { DoExecute = new Action<object>(DrawRect) };
            DiscernComand = new SimpleCommand { DoExecute = new Action<object>(DiscernAction) };
        }

        /// <summary>
        /// 识别二维码对应逻辑
        /// </summary>
        /// <param name="obj"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void DiscernAction(object obj)
        {
            // 第一步：需要把二维码识别区域找出来
            // 灰度化
            HOperatorSet.Rgb1ToGray(DispImage, out HObject GrayImage);
            // 生成刚刚画ROI区域对应矩形
            var roiPoint = _roi.HTuples;
            HObject genRoi = null;
            switch (_shapeType)
            {
                case ShapeType.Cricle:
                    HOperatorSet.GenCircle(out genRoi, roiPoint[0].D, roiPoint[1].D, roiPoint[2].D);
                    break;
                case ShapeType.Rectangle:
                    HOperatorSet.GenRectangle1(out genRoi, roiPoint[0].D, roiPoint[1].D, roiPoint[2].D, roiPoint[3].D);
                    break;
            }
            // 抠图
            HOperatorSet.ReduceDomain(GrayImage, genRoi, out HObject ImageReduced);
            HOperatorSet.CropDomain(ImageReduced, out HObject ImagePart);
            // 把最终结果赋值给ROI对象
            DispROI = ImagePart;
            // 第二步：创建对应的二维码识别模型并开始识别，显示绑定结果
            // 设置编码格式
            HOperatorSet.SetSystem("filename_encoding", "utf8");
            // 创建二维码识别，不知道你要识别的二维码类型
            // HOperatorSet.CreateDataCode2dModel(new HTuple("QR Code"), new HTuple(), new HTuple(), out HTuple CodeHandle);
            var codeModes = new HTuple("Aztec Code", "Data Matrix ECC 200", "DotCode", "GS1 Aztec Code", "GS1 DataMatrix", "GS1 DotCode", "GS1 QR Code", "Micro QR Code", "PDF417", "QR Code");
            for (int i = 0; i < codeModes.Length; i++)
            {
                var codeMode = codeModes.TupleSelect(i);
                Debug.WriteLine($"codeMode={codeMode}");
                // 创建二维码模型
               
                HOperatorSet.CreateDataCode2dModel(codeMode, new HTuple(), new HTuple(), out HTuple CodeHandle);
               
                // 添加额外参数
                //这个参数时设置极性用的，就是防止码并非是白底黑字
                HOperatorSet.SetDataCode2dParam(CodeHandle, "polarity", "any");
                //设置超时时间
                HOperatorSet.SetDataCode2dParam(CodeHandle, "timeout", 1000);
                //防止误识别设置，因为某些二维码模型没有这个属性，会报错所以try以下
                try
                {
                    HOperatorSet.SetDataCode2dParam(CodeHandle, "strict_quiet_zone", "yes");
                }
                catch (HalconException)
                {
                    continue;
                }
                // 开始识别结果
                HOperatorSet.FindDataCode2d(GrayImage, out HObject ho_SymbolXLDs, CodeHandle,
                    "stop_after_result_num", 1000, out HTuple hv_ResultHandles, out HTuple hv_DecodedDataStrings);
                // 统计识别结果
                HOperatorSet.CountObj(ho_SymbolXLDs, out HTuple hv_Number);
                if (hv_Number.I != 0) 
                {
                    HOperatorSet.SetColor(_hv_Hanlde, new HTuple("green"));
                    // 赋值轮廓对象
                    XLDObject = ho_SymbolXLDs;
                    // 赋值识别结果
                    CodeData = hv_DecodedDataStrings.S;
                    break;
                }

                //清除ROI
                ClearROI();

            }
        }

        /// <summary>
        /// 清除ROI区域
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void ClearROI()
        {
            _roi.DrawingObject.Dispose();
        }

        public HObject DispImage
        {
            get { return _dispImage; }
            set { _dispImage = value; RiseProperty(nameof(DispImage)); }
        }

        public HObject DispROI
        {
            get { return _dispROI; }
            set { _dispROI = value; RiseProperty(nameof(DispROI)); }
        }

        public HObject XLDObject
        {
            get { return _dispXld; }
            set { _dispXld = value; RiseProperty(nameof(XLDObject)); }
        }

        public string CodeData
        {
            get { return _codeData; }
            set { _codeData = value; RiseProperty(nameof(CodeData)); }
        }

        /// <summary>
        /// 执行画矩形的逻辑
        /// </summary>
        /// <param name="obj"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void DrawRect(object obj)
        {
            // 指定形状类型
            _shapeType = ShapeType.Rectangle;
            if (_myCanvas != null)
            {
                // 显示画布
                _myCanvas.Visibility = Visibility.Visible;
            }
            
        }

        /// <summary>
        /// 初始化的时候获取Halcon控件对象
        /// </summary>
        /// <param name="windowControlWPF"></param>
        public MainWindowViewModel(HSmartWindowControlWPF windowControlWPF) : this()
        {
            _controlWPF = windowControlWPF;
        }

        /// <summary>
        /// 鼠标按下的命令执行逻辑
        /// </summary>
        /// <param name="obj"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void MouseDown(object obj)
        {

            if (Mouse.LeftButton == MouseButtonState.Pressed) 
            {
                _hv_Hanlde = _controlWPF.HalconWindow;
                _myCanvas = obj as Canvas;
                _startPoint = Mouse.GetPosition(_myCanvas);
                // 获取窗口加载的图片部分对象
                var imagePart = _controlWPF.HImagePart;
                // 获取图片与窗口的高度比
                _k = imagePart.Height / _controlWPF.ActualHeight;
                // 获取图片部分在窗口的坐标
                _tx = imagePart.X;
                _ty = imagePart.Y;
                // 如果缩放窗口，那么比例值肯定要变化
                var hdp = DependencyPropertyDescriptor
                    .FromProperty(HSmartWindowControlWPF.HImagePartProperty, typeof(HSmartWindowControlWPF));
                hdp.AddValueChanged(_controlWPF, (o, e) => 
                {
                    imagePart = _controlWPF.HImagePart;
                    // 获取图片与窗口的高度比
                    _k = imagePart.Height / _controlWPF.ActualHeight;
                    // 获取图片部分在窗口的坐标
                    _tx = imagePart.X;
                    _ty = imagePart.Y;
                });
            }
        }

        private void MouseMove(object obj)
        {
            if (Mouse.LeftButton == MouseButtonState.Pressed)
            {
                _endPoint = Mouse.GetPosition(_myCanvas);
                // 计算画矩形的长和高
                var width = Math.Abs(_endPoint.X - _startPoint.X);
                var height = Math.Abs(_endPoint.Y - _startPoint.Y);
                // 设置矩形在Canvas上面的定位
                var top = _startPoint.Y;
                var left = _startPoint.X;

                switch (_shapeType)
                {
                    case ShapeType.Cricle:
                        break;
                    case ShapeType.Rectangle:
                        // 设置属性的值
                        RectModel.RectangleWidth = width;
                        RectModel.RectangleHeight = height;
                        RectModel.RectangleLeft = left;
                        RectModel.RectangleTop = top;
                        // 把图像坐标转换为Halcon坐标
                        ConvertToHalconPoint(_startPoint.X, _startPoint.Y, _k, _tx, _ty, out double column, out double row);
                        ConvertToHalconPoint(_endPoint.X, _endPoint.Y, _k, _tx, _ty, out double column1, out double row1);
                        _row = row;
                        _column = column;
                        _row1 = row1;
                        _column1 = column1;
                        break;
                    default:
                        break;
                }
                
                
            }
        }

        /// <summary>
        /// 鼠标松开的方法
        /// </summary>
        /// <param name="obj"></param>
        private void MouseUp(object obj)
        {
            if (DispImage != null && _myCanvas != null)
            {
                // 应该根据选择ROI类型绘制对应图像放到Halcon窗口上面
                switch (_shapeType)
                {
                    case ShapeType.Cricle:
                        break;
                    case ShapeType.Rectangle:
                        var rectTuple = new HTuple[] { _row, _column, _row1, _column1 };
                        // 绘制矩形对象
                        var rect = HDrawingObject.CreateDrawingObject(HDrawingObject.HDrawingObjectType.RECTANGLE1, rectTuple);
                        _roi = new NewDrawingObject { DrawingObject = rect, HTuples = rectTuple };
                        // 把矩形放到Halcon窗口
                        _hv_Hanlde.AttachDrawingObjectToWindow(rect);
                        break;
                    default:
                        break;
                }

                // 设置ROI区域的拖拽及缩放事件
                if (_roi!= null)
                {
                    _roi.DrawingObject.OnDrag(DragCallbackClass);
                    _roi.DrawingObject.OnResize(ResizeCallbackClass);
                }

                _myCanvas.Visibility = Visibility.Collapsed;
                RectModel.InitRectangle();
            }
           
        }

        public void DragCallbackClass(HDrawingObject drawid, HWindow window, string type)
        {
            RefreshAction(drawid);
        }

        public void ResizeCallbackClass(HDrawingObject drawid, HWindow window, string type)
        {
            RefreshAction(drawid);
        }

        private void RefreshAction(HDrawingObject drawid)
        {
            // 根据请求绘制的ROI区域类型获取对应属性元组
            HTuple attrValues = null;
            switch (_shapeType)
            {
                case ShapeType.Cricle:
                    var criAttrTuple = new HTuple("row","column","radius");
                    attrValues = drawid.GetDrawingObjectParams(criAttrTuple);
                    break;
                case ShapeType.Rectangle:
                    var rectAttrTuple = new HTuple("row1", "column1", "row2","column2");
                    attrValues = drawid.GetDrawingObjectParams(rectAttrTuple);
                    break;
            }
            // 根据获取的元组数组封装对应ROI类型的属性值元组数据
            HTuple[] tuples = new HTuple[attrValues.Length];
            for (int i = 0; i < attrValues.Length; i++)
            {
                tuples[i] = attrValues[i];
            }

            // 确定当前操作的ROI区域是否为当前区域对象
            if (_roi.DrawingObject.ID== drawid.ID) 
            {
                _roi.HTuples= tuples;
            }

        }




        /// <summary>
        /// 执行图片加载逻辑的方法
        /// </summary>
        /// <param name="obj"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void LoadImage(object obj)
        {
            //清空ROI
            if (_hv_Hanlde!= null) 
            {
                _hv_Hanlde.ClearWindow();
                XLDObject = new HObject();
                DispROI = new HObject();
                CodeData = null;
            }

            var fileDialog = new OpenFileDialog();
            fileDialog.Filter = "打开图片|*.png;*.jpg;*.bmp";
            fileDialog.DefaultExt = "*.png";
            if (fileDialog.ShowDialog() == true)
            {
                // 获取打开图片路径
                var fileName = fileDialog.FileName;
                // 创建一个HImage对象
                var ho_image = new HImage(fileName);
                // 赋值给属性
                DispImage = ho_image;
            }
        }

        /// <summary>
        /// 把图像坐标转换为Halcon坐标系
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="k"></param>
        /// <param name="tx"></param>
        /// <param name="ty"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        private void ConvertToHalconPoint(double x, double y, double k, double tx, double ty, out double row, out double column)
        {
            row = k * x + tx;
            column = k * y + ty;
        }
    }

    
}
